%{
	//#include "lexico.h" 
	#include "tablasimbolos.h"
	#include <stdio.h>
	#include <stdlib.h>
	#include <math.h>
	#include <string.h>
	extern int yylex();
	extern char *yytext;
	extern FILE *yyin;
	extern int debugs;
	int yyerror(char *s);
	int nrolinea = 1;	
	
	void install_symbol(char *);
	void errorSemantico(char *);
	int get_tipo1(char *);

	
	
	
	
	struct types {
		char *lexema;
		int tipo;
		int alcance;
	};
%}


%union {
	
	char *lexema;
	struct types *tipos;
}
	
%token <lexema> TID
%token TPARA
%token TPARC
%token TCRA
%token TCRC
%token TLLA
%token TLLC
%token TCOMA
%token TPCOMA
%token T2PUNTOS
%token TIGUAL
%token TASIGN
%token TPUNTO
%token TMAS
%token TMENOS
%token TMULT
%token TDIV
%token TAND
%token TOR
%token TMAY
%token TMEN
%token TMAYIG
%token TMENIG
%token TDIF

%token TARRAY
%token TBREAK
%token TDO
%token TELSE
%token TEND
%token TFOR
%token TIF
%token TIN
%token TLET
%token <lexema> TNIL
%token TOF
%token TTHEN
%token TTO
%token TTYPE
%token TVAR
%token TWHILE 

%token <lexema> TCSTRING
%token <lexema> TCTEINT

	
%nonassoc TTHEN
%left TELSE
%nonassoc TASIGN
%left TOR
%left TAND
%nonassoc TIGUAL TDIF TMAY TMAYIG TMEN TMENIG
%left TMAS TMENOS
%left TMULT TDIV
%right TMENOSU
%nonassoc TDO
%nonassoc TOF

%type <tipos> exp
%type <tipos> type_id
%type <tipos> ty
%type <tipos> lvalue

%%
/* -------------------------------------------------------------------------- */


prog :  exp {
				install_symbol("string");	
				add_tipo(get_symbol("string"), 2);
				install_symbol("int");	
				add_tipo(get_symbol("int"), 1);
				
            }                                                             
	 | decs
/* -------------------------------------------------------------------------- */	
exp : TPARA exp TPARC                                                                                     
	| lvalue                                                                                         
	| TPARA TPARC                                                                                                  
    | TNIL     { $$ = (struct types *)malloc(sizeof(struct types));
		         $$->tipo = 3;
				 $$->lexema = (char *)strdup($1);
			   }                                                                                                          
	| TCTEINT  { $$ = (struct types *)malloc(sizeof(struct types));			 
				 $$->tipo = 1; 
				 $$->lexema = (char *)strdup($1);
		
               }                                                                                                                
	| TCSTRING { $$ = (struct types *)malloc(sizeof(struct types));
				 $$->tipo = 2; 
				 $$->lexema = (char *)strdup($1);
		        		
			   }
	/* operaciones */
	| exp TMAS exp	{ $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
					}	  		
	| exp TMENOS exp{ $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
					}
	| exp TMULT exp { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
		            }
	| exp TDIV exp  { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
		            }
	| exp TIGUAL exp{ $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
		                  $$->tipo = 1;	
		            }
    | exp TDIF exp  { $$ = (struct types *)malloc(sizeof(struct types));
	                  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
		            }
	| exp TMAY exp  { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
				   	}
    | exp TMEN exp  { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
		            }
	| exp TMAYIG exp{ $$ = (struct types *)malloc(sizeof(struct types));
				      if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;		
					}
	| exp TMENIG exp{ $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
					}
	| exp TAND exp  { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
					}
	| exp TOR exp   { $$ = (struct types *)malloc(sizeof(struct types));
					  if( ($1->tipo == $3->tipo) && ($1->tipo == 1))
						  $$->tipo = 1;	
					}
	/* ----------------------------- */
	| TMENOS exp %prec TMENOSU
	| type_id TLLA record_fields TLLC
	| lvalue TCRA exp TCRC TOF exp  { $$ = (struct types *)malloc(sizeof(struct types));
									  int tipo = get_tipo1($1->lexema);
									  $$->tipo = tipo;
									  if($3->tipo == 1){ }
										
		                              else
										  printf("Error Semantico en la linea %d:  el tamaño de los arreglos debe ser de tipo entero\n", nrolinea );
															   
														 									
									}
	| TPARA exp TPCOMA explist TPARC 
    /* asignacion */
	| lvalue TASIGN exp
	/* ----------------------------- */
	/* estructuras de control */
	| if_st
	| while_st
    | for_st
	| let_st
	| TBREAK 
	/* ----------------------------- */


/* -------------------------------------------------------------------------- */	
explist: exp
	   | exp TPCOMA explist
	   

/* -------------------------------------------------------------------------- */
record_fields : /* vacio */
			  | type_id TIGUAL exp TCOMA record_fields   
			  | type_id TIGUAL exp                                                                                      
			   
/* -------------------------------------------------------------------------- */																										
decs: dec decls                                                                                      
	
/* -------------------------------------------------------------------------- */
decls: /* vacio */
     | dec decls                                                                                       
	                                                                                                                              	
/* -------------------------------------------------------------------------- */	
dec : tydec 
	| vardec                                                                                         
                                                                                                     
	
/* -------------------------------------------------------------------------- */	
vardec : TVAR type_id TASIGN exp { if(get_symbol($2->lexema) == NULL)
	   							   { 
	   								   install_symbol($2->lexema);									   
									   add_tipo(get_symbol($2->lexema), $4->tipo);
									   add_context(get_symbol($2->lexema),0);
								   }
								   else
								   {
									   printf("Error Semantico en la linea %d: la variable %s ya ha sido declarada\n", nrolinea, $2->lexema );
								   }								   
                                 }                                                     
       | TVAR type_id T2PUNTOS type_id TASIGN exp { if(get_symbol($2->lexema) == NULL)
												  	{	
														struct registro *tmpreg;
														install_symbol($2->lexema);
														for(tmpreg = ST; tmpreg!= NULL; tmpreg = tmpreg->sgte)
														{
															if(strcmp(tmpreg->id, $4->lexema) == 0)
																add_tipo(get_symbol($2->lexema), tmpreg->atributos->tipo);
															    add_context(get_symbol($2->lexema),0);
																
														}
														//printf("%d\n", $6->tipo);														
														int tipo = get_tipo1($4->lexema);
														if( ($6->tipo != tipo) && ($6->tipo != 3))
															printf("Error Semantico en la linea %d:  incompatibilidad de tipos en la asignacion\n", nrolinea );
												   	}
												   	else
												   	{
														printf("Error Semantico en la linea %d: la variable %s ya ha sido declarada\n", nrolinea, $2->lexema );
												   	}													
	                                              }
	   | error { yyerror("No se ha colocado el simbolo: var, en la declaracion de variables"); yyerrok;  } type_id TASIGN exp
	   | TVAR type_id error { yyerror("No se ha colocado el simbolo: :=, en la declaracion de variables");  } exp
	   | error { yyerror("Error en la declaracion de variables"); }

/* -------------------------------------------------------------------------- */
tydec: TTYPE type_id TIGUAL ty { if(get_symbol($2->lexema) == NULL)
							   	 { 
							   		install_symbol($2->lexema);
							   		add_tipo(get_symbol($2->lexema), $4->tipo);
							   	 }								 
							   	 else
							   	 {
									 printf("Error Semantico en la linea %d: el tipo %s ya ha sido declarada\n", nrolinea, $2->lexema );
							  	 }							 
							   }

/* -------------------------------------------------------------------------- */
ty : type_id { $$ =(struct types *)malloc(sizeof(struct types));
			   $$->tipo = $1->tipo;
			 }

	| TARRAY TOF type_id { $$ =(struct types *)malloc(sizeof(struct types));
						   $$->tipo = 5;					
						 }                                                                          
	| TLLA tyfields TLLC { $$ =(struct types *)malloc(sizeof(struct types));
						   $$->tipo = 4;
		                 }                                                  

/* -------------------------------------------------------------------------- */
tyfields : /* vacio */
		 | tyfield
		 | tyfield TCOMA tyfields                          
		 
                                                                                                                                       
/* -------------------------------------------------------------------------- */
tyfield : type_id T2PUNTOS type_id { install_symbol($1->lexema);
						             //add_tipo(get_symbol($1->lexema), $3->tipo);								
								   }


/* -------------------------------------------------------------------------- */
type_id : TID { $$ =(struct types *)malloc(sizeof(struct types));				
				$$->lexema = (char *)strdup($1);				
				
				if(strcmp($1, "int") == 0)
					$$->tipo = 1;
				else if(strcmp($1, "string") == 0)
					$$->tipo = 2;
				else if(strcmp($1, "nil") == 0)
						$$->tipo = 3;				
				else
					$$->tipo = -1;
              }
                                                                                                                                   
/* -------------------------------------------------------------------------- */
lvalue : type_id   { $$ =(struct types *)malloc(sizeof(struct types));
					 $$->lexema = $1->lexema;
				   }                                                                                                           
	   | lvalue TPUNTO type_id                                                                   
       | lvalue TCRA exp TCRC

/* -------------------------------------------------------------------------- */
let_st : TLET decs TIN TEND { yyerrok; }                                                            
	   | TLET decs TIN exp TEND { yyerrok; }                                     
       | TLET decs TIN exp TPCOMA explist TEND { yyerrok; }

/* -------------------------------------------------------------------------- */
if_st : TIF exp TTHEN exp { yyerrok; } 
	  | TIF error { yyerror("No se ha declarado una expresion despues del simbolo: if"); yyerrok; } TTHEN exp
	  | TIF exp TTHEN error { yyerror("No se ha declarado una expresion despues del simbolo: then"); yyerrok; }
      | TIF exp TTHEN exp TELSE exp { yyerrok; }	  
	  | TIF exp TTHEN exp TELSE error { yyerror("No se ha declarado una expresion despues del simbolo: else"); yyerrok; }

/* -------------------------------------------------------------------------- */
while_st : TWHILE exp TDO exp { yyerrok; }
		 | TWHILE error { yyerror("No se ha declarado una expresion despues del simbolo: while"); yyerrok; } TDO exp		
         | TWHILE exp TDO error { yyerror("No se ha declarado una expresion despues del simbolo: do"); yyerrok; }

/* -------------------------------------------------------------------------- */
for_st : TFOR type_id TASIGN exp TTO exp TDO exp { if(($4->tipo ==$6->tipo) && ($4->tipo == 1)){}																					
												   else
												   {
													   printf("Error Semantico en la linea %d:  incompatibilidad de tipos en el for\n", nrolinea );
												   }
														install_symbol($2->lexema);									   
													    add_tipo(get_symbol($2->lexema), $4->tipo);
														add_context(get_symbol($2->lexema),1);

												  yyerrok; }
	   | TFOR error { yyerror("No se ha declarado una expresion despues del simbolo: for"); yyerrok; } TTO exp TDO exp
	   | TFOR type_id TASIGN exp TTO error { yyerror("No se ha declarado una expresion despues del simbolo: to"); yyerrok; } TDO exp
       | TFOR type_id TASIGN exp TTO exp TDO error { yyerror("No se ha declarado una expresion despues del simbolo: do"); yyerrok; }

/* -------------------------------------------------------------------------- */
%%
int yyerror(char *s)
{
	
	if (strcmp(s,"syntax error") != 0)
		printf(" Error de Sintaxis en la linea %d: %s \n", nrolinea, s);
	else
		printf(" Error de Sintaxis en la linea %d, cerca al simbolo %s \n", nrolinea, yytext);
	return 0;
}


void install_symbol(char *name)
{
    put_symbol(name);
}


void errorSemantico(char *s)
{
	printf("Error Semantico en la linea %d, la variable %s ha sido declarada ", nrolinea, s);
}

int get_tipo1(char *nombre)
{	
	int tipo;
	struct registro *record;
	record = get_symbol(nombre);
	if (record != NULL)
		tipo = get_tipo(record);
	else
		tipo = -1;
	return tipo;
}

